using System.Buffers;
using ProtoBuf;
using SuperSocket.ProtoBase;

namespace Core;

/// <summary>
/// | bodyLength | body |
/// | header | cmd | body |
/// </summary>
public sealed class PlayPipeLineFilter : FixedHeaderPipelineFilter<PlayPacket>
{
    private static readonly Dictionary<CommandKey,IPacketFactory> PacketFactorys = new();

    static PlayPipeLineFilter()
    {
        var type = typeof(ProtobufPacketFactory<>);

        foreach (var command in PlayPacket.CommandTypes)
        {
            var genericType = type.MakeGenericType(command.Value);

            var packetFactory = Activator.CreateInstance(genericType) as IPacketFactory;

            if (packetFactory == null)
                continue;

            PacketFactorys.TryAdd(command.Key, packetFactory);
        }
    }

    interface IPacketFactory
    {
        PlayPacket Create(ref SequenceReader<byte> body);
    }

    class ProtobufPacketFactory<TPacket> : IPacketFactory
        where TPacket : PlayPacket, new()
    {
        public PlayPacket Create(ref SequenceReader<byte> reader)
        {
            // 获取剩下的字节数 
            return Serializer.Deserialize<TPacket>(reader.UnreadSequence);
        }
    }

    private const byte HeaderLength = 2;

    public PlayPipeLineFilter()
        : base(HeaderLength)
    {
    }

    protected override PlayPacket DecodePackage(ref ReadOnlySequence<byte> buffer)
    {
        var reader = new SequenceReader<byte>(buffer.Slice(HeaderLength));

        reader.TryRead(out var command);

        var key = (CommandKey)command;

        if (!PacketFactorys.TryGetValue(key, out var packetFactory))
            throw new Exception("");

        var packet = packetFactory.Create(ref reader);

        packet.Key = key;

        return packet;
    }

    protected override int GetBodyLengthFromHeader(ref ReadOnlySequence<byte> buffer)
    {
        var reader = new SequenceReader<byte>(buffer);

        reader.TryReadLittleEndian(out short bodyLength);

        return bodyLength;
    }
}